﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LEVUtilityLibrary
{
    public class BatteryPack_UARTPacketFormat
    {
        private const byte LeadingCode = (0x3A);
        private const byte SlaveAddressCode = (0x16);
        private const byte EndCode1 = (0x0D);
        private const byte EndCode2 = (0x0A);
        private const byte Respond_Error_Check_Code = (0xF3);
        private const byte Respond_Accept_Check_Code = (0xF0);

        //========Transmiting Data Structure===========================
        //typedef struct{
        //    static char cStart = 0X3A;	//起始字元
        //    unsigned char 0X16;		//Slave Address
        //    unsigned char Command;		//應回應的命令
        //    unsigned char LenExpected;	//數據長度
        //    unsigned char DataBuf[DATA_BUF_NUM];//數據內容
        //    unsigned char LRCDataLow;	    //checkSum with slave Low byte, included slave address, command, length and data.
        //    unsigned char LRCDataHigh;	//checkSum with slave High byte, included slave address, command, length and data.
        //    static char cEND1= 0X0D;	//結束字元 1 
        //    static char cEND1= 0X0A;	//結束字元 2
        //} LEV Protocol Packet;
        public static byte[] Packing(byte TransmittedCmd, byte[] TransmittedParameter)
        {
            List<byte> TransmitData = new List<byte>();
            byte LenExpected = (byte)TransmittedParameter.Length;
            TransmitData.Add(SlaveAddressCode);
            TransmitData.Add(TransmittedCmd);
            TransmitData.Add(LenExpected);
            TransmitData.AddRange(TransmittedParameter);


            byte[] CheckBuffer = TransmitData.ToArray<Byte>();
            ushort checkSum = MassUtilities.ComputeCheckSum16(CheckBuffer);

            TransmitData.Add((byte)(checkSum));           // low byte     //4 to last byte for packet
            TransmitData.Add((byte)(checkSum >> 8));      // high byte    //3 to last byte for packet
            TransmitData.Add(EndCode1);                //2 to last byte for packet
            TransmitData.Add(EndCode2);                //last byte for packet

            TransmitData.Insert(0, LeadingCode);        // add first Item

            return TransmitData.ToArray<Byte>();
        }

        //=======Receiving Data Structure===============================
        //typedef struct{
        //    static char cStart = 0X3A;	//起始字元
        //    unsigned char 0X16;		    //Slave Address
        //    unsigned char Command;		//命令
        //    unsigned char LenExpected;	//數據長度
        //    unsigned char DataBuf[DATA_BUF_NUM];//數據內容
        //    unsigned char LRCDataLow;	    //checkSum with slave Low byte, included slave address, command, length and data.
        //    unsigned char LRCDataHigh;	//checkSum with slave High byte, included slave address, command, length and data.
        //    static char cEND1= 0X0D;	//結束字元 1 
        //    static char cEND1= 0X0A;	//結束字元 2
        //} LEV Protocol Packet;
        public static bool Unpacking(byte[] ReceivedRawData, out byte ReceivedCommand, out byte[] ReceivedParameter)
        {
            int segStartIdxOfRawData = 0;
            int segEndIdxOfRawData = 0;
            return Unpacking(ReceivedRawData, out ReceivedCommand, out ReceivedParameter, out segStartIdxOfRawData, out segEndIdxOfRawData);
        }
        public static bool Unpacking(byte[] ReceivedRawData, out byte ReceivedCommand, out byte[] ReceivedParameter, out int segStartIdxOfRawData, out int segEndIdxOfRawData)
        {
            bool IsFound_Packet_Form = false;
            segStartIdxOfRawData = 0;
            segEndIdxOfRawData = 0;
            ReceivedCommand = 0;
            ReceivedParameter = new byte[0];
            List<byte> ReceivedDataList = new List<byte>();

            int startFormIndex;
            int dataLength, endCode1_idx, endCode2_idx;

            if (ReceivedRawData.Length < 2)
            {
                return IsFound_Packet_Form;
            }


            for (int i = 0; i < (ReceivedRawData.Length - 1); i++)
            {
                //finding leading codes
                if ((ReceivedRawData[i] == LeadingCode) && (ReceivedRawData[i + 1] == SlaveAddressCode))
                {
                    startFormIndex = i;
                    if ((startFormIndex + 3) >= ReceivedRawData.Length)
                    {
                        return IsFound_Packet_Form;
                    }
                    dataLength = ReceivedRawData[startFormIndex + 3];    //offset 3 to get receiving data length
                    endCode1_idx = startFormIndex + 3 + dataLength + 2 + 1;  //add offset 2 is two of Cuecksum bytes
                    endCode2_idx = startFormIndex + 3 + dataLength + 2 + 2;  //add offset 2 is two of Cuecksum bytes
                    if (endCode2_idx >= ReceivedRawData.Length)
                    {
                        return IsFound_Packet_Form;
                    }
                    //finding Ending Codes
                    if ((ReceivedRawData[endCode1_idx] == EndCode1) && (ReceivedRawData[endCode2_idx] == EndCode2))
                    {
                        //calculate checkSum
                        byte[] CheckBuffer = new byte[dataLength + 3]; //included slave address, command, length and data.
                        //[bug] 20140916 hsinmo modified
                        //Array.Copy(ReceivedRawData, startFormIndex + 2, CheckBuffer, 0, CheckBuffer.Length);
                        Array.Copy(ReceivedRawData, startFormIndex + 1, CheckBuffer, 0, CheckBuffer.Length);
                        ushort checkSum = MassUtilities.ComputeCheckSum16(CheckBuffer);
                        int checkSumLowByte_Index = endCode1_idx - 2;
                        int checkSumHighByte_Index = checkSumLowByte_Index + 1;
                        if (ReceivedRawData[checkSumLowByte_Index] == ((byte)(checkSum)) && ReceivedRawData[checkSumHighByte_Index] == ((byte)(checkSum >> 8)))
                        {
                            //Save data to structure
                            ReceivedCommand = ReceivedRawData[startFormIndex + 2];

                            for (byte j = 0; j < dataLength; j++)
                            {
                                ReceivedDataList.Add(ReceivedRawData[startFormIndex + 4 + j]);
                            }
                            segStartIdxOfRawData = startFormIndex;
                            segEndIdxOfRawData = startFormIndex + 4 + dataLength - 1 + 2 + 2;//add 2bytes checksum , add 2bytes endCode
                            IsFound_Packet_Form = true;
                            break;
                        }
                    }//if((ReceivingData[endCode1_idx] == EndingCode1) && (ReceivingData[endCode2_idx] == EndingCode2)){
                }//if((ReceivingData[i] == LeadingCode) && (ReceivingData[i+1] == SlaveAddressCode)){
            }//for(int i = 0; i < (ReceivingData.Length - 1); i++){
            if (IsFound_Packet_Form)
            {
                ReceivedParameter = ReceivedDataList.ToArray<byte>();
            }
            return IsFound_Packet_Form;
        }
    }//public class BatteryPack_UARTPacketFormat
}//namespace LEVUtilityLibrary
